#include "comm/my_cleanup.h"
#include "comm/my_hooks.h"
#include "comm/my_defs.h"
#include "config/my_cache_conf.h"
#include "event/my_event_loop.h"
#include "event/my_worker.h"
#include "event/my_aio.h"

my_aio_manager_t aio_manager;

typedef struct {
    int                 step;
    int                 fd;
    char                *buf;
    size_t              buf_size;
    off_t               offset;
    my_aio_request_t    aio_req;
} my_test_data_t;

static inline void
my_test_aio_handler(my_dispatch_event_t *dispatch_event)
{
    my_test_data_t *data = dispatch_event->data;
    my_aio_request_t *aio_req = &data->aio_req;

    if (data->step == 0) {
        data->step++;
        my_aio_reqeuest_init(aio_req, MY_AIO_READ, data->fd,
            data->buf, data->buf_size, 0, my_test_aio_handler, data);
        my_aio_post_event(&aio_manager, aio_req);
        return;
    }

    if (data->step == 1) {
        data->step++;

        if (aio_req->res.eno != 0) {
            MY_LOG_FATAL("aio_read failed, errno: %d", aio_req->res.eno);
        }

        MY_LOG_DEBUG("aio_read success, read n: %d, exec_time: %d",
            aio_req->res.res, aio_req->down_time - aio_req->setup_time);
        write(STDOUT_FILENO, aio_req->buf, (size_t)aio_req->res.res);
        printf("\n");
        my_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    if (data->step == 2) {
        data->step++;
        for (size_t i = 0; i < data->buf_size; i++) {
            data->buf[i] = 'b';
        }
        my_aio_reqeuest_init(aio_req, MY_AIO_WRITE, data->fd,
            data->buf, data->buf_size, 0, my_test_aio_handler, data);
        my_aio_post_event(&aio_manager, aio_req);
        return;
    }

    if (data->step == 3) {
        data->step++;

        if (aio_req->res.eno != 0) {
            MY_LOG_FATAL("aio_write failed, errno: %d", aio_req->res.eno);
        }

        MY_LOG_DEBUG("aio_write success, write: %d, exec_time: %d",
            aio_req->res.res, aio_req->down_time - aio_req->setup_time);
        my_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    if (data->step == 4) {
        data->step++;
        my_aio_reqeuest_init(aio_req, MY_AIO_READ, data->fd,
            data->buf, data->buf_size, 0, my_test_aio_handler, data);
        my_aio_post_event(&aio_manager, aio_req);
        return;
    }

    if (data->step == 5) {
        data->step++;

        if (aio_req->res.eno != 0) {
            MY_LOG_FATAL("aio_read failed, errno: %d", aio_req->res.eno);
        }

        MY_LOG_DEBUG("aio_read success, read n: %d, exec_time: %d",
            aio_req->res.res, aio_req->down_time - aio_req->setup_time);
        write(STDOUT_FILENO, aio_req->buf, (size_t)aio_req->res.res);
        printf("\n");
        my_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    if (data->step == 6) {
        data->step++;
        my_aio_reqeuest_init(aio_req, MY_AIO_READ_PING, data->fd,
            data->buf, data->buf_size, 0, my_test_aio_handler, data);
        my_aio_post_event(&aio_manager, aio_req);
        return;
    }

    if (data->step == 7) {
        data->step++;
        MY_LOG_DEBUG("aio_read_ping, exec_time: %d",
            aio_req->res.res, aio_req->down_time - aio_req->setup_time);
        my_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    if (data->step == 8) {
        data->step++;
        my_aio_reqeuest_init(aio_req, MY_AIO_WRITE_PING, data->fd,
            data->buf, data->buf_size, 0, my_test_aio_handler, data);
        my_aio_post_event(&aio_manager, aio_req);
        return;
    }

    if (data->step == 9) {
        data->step++;
        MY_LOG_DEBUG("aio_write_ping, exec_time: %d",
            aio_req->res.res, aio_req->down_time - aio_req->setup_time);
        my_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    MY_LOG_DEBUG("test down");
}

int main()
{
    my_hooks_init();

    my_cache_conf_init();

    my_worker_processor_start();

    my_aio_manager_start(&aio_manager,
        1, 1, 10, 10);

    int fd = open("/tmp/1.txt", O_CREAT|O_RDWR, 0644);
    char buf[1024];
    for (size_t i = 0; i < sizeof(buf); i++) {
        buf[i] = 'a';
    }
    write(fd, buf, sizeof(buf));

    my_test_data_t test_data;
    bzero(&test_data, sizeof(my_test_data_t));
    test_data.fd = fd;
    test_data.buf = buf;
    test_data.buf_size = sizeof(buf);
    test_data.offset = 0;

    my_dispatch_event_t dispatch_event;
    bzero(&dispatch_event, sizeof(my_dispatch_event_t));
    dispatch_event.handler = my_test_aio_handler;
    dispatch_event.data = &test_data;
    my_worker_processor_post_event(&dispatch_event);

    sleep(1);

    close(fd);

    my_aio_manager_stop(&aio_manager);

    my_worker_processor_stop();

    my_cleanup_list_exec(&g_cleanup_list);

    my_mem_assert_leak();

    MY_LOG_DEBUG("test pass");

    return 0;
}